using System;
using System.Collections.Specialized;
using System.IO;
using System.Net.Sockets;
using OracleInternal.Common;

namespace OracleInternal.Network
{
	internal class WssTransportAdapter : ITransportAdapter
	{
		internal const string WSS_PROTOCOL = "wss";

		internal const string WS_PROTOCOL = "ws";

		protected bool m_Connected;

		protected bool m_WSS;

		protected ConOraBufPool m_OraBufPool;

		protected ConnectionOption m_conOption;

		protected WebSocketStream m_WebSocketStream;

		private ITransportAdapter m_TcpConnection;

		public ConOraBufPool OraBufPool
		{
			set
			{
				m_OraBufPool = value;
			}
		}

		public bool Connected
		{
			get
			{
				if (m_WebSocketStream.State != WebSocketStream.WebSocketState.Connected)
				{
					return false;
				}
				return true;
			}
		}

		public bool NeedReneg => m_WSS;

		internal WssTransportAdapter(NameValueCollection socketOptions)
		{
		}

		internal WssTransportAdapter(ConnectionOption conOption, ITransportAdapter tcpConnection, WebSocketStream webSocketStream)
		{
			m_TcpConnection = tcpConnection;
			m_WebSocketStream = webSocketStream;
		}

		public void Connect(ConnectionOption conOption)
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.Connect);
			}
			m_conOption = conOption;
			CreateTcpConnection(conOption);
			m_TcpConnection.Connect(conOption);
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.Connect);
			}
		}

		public Stream ConnectIterate()
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.ConnectIterate);
			}
			m_WebSocketStream = null;
			Stream stream = m_TcpConnection.ConnectIterate();
			if (stream != null)
			{
				m_WebSocketStream = new WebSocketStream(m_conOption, stream);
				m_WebSocketStream.Handshake(WebSocketStream.WebSocketRoles.WebSocketClient);
				if (m_WebSocketStream.State != WebSocketStream.WebSocketState.Connected)
				{
					if (ProviderConfig.m_bTraceLevelNetwork)
					{
						Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Sqlnet, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.ConnectIterate, "WebSocket failed to connect\n");
					}
					throw new NetworkException(12538);
				}
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.ConnectIterate);
			}
			return m_WebSocketStream;
		}

		public void Listen(ConnectionOption conOption)
		{
			CreateTcpConnection(conOption);
			m_TcpConnection.Listen(conOption);
		}

		public ITransportAdapter Answer(ConnectionOption conOption)
		{
			ITransportAdapter transportAdapter = m_TcpConnection.Answer(conOption);
			WebSocketStream webSocketStream = new WebSocketStream(conOption, transportAdapter.GetStream());
			webSocketStream.Handshake(WebSocketStream.WebSocketRoles.WebSocketServer);
			if (m_WebSocketStream.State == WebSocketStream.WebSocketState.Connected)
			{
				return new WssTransportAdapter(conOption, transportAdapter, webSocketStream);
			}
			return null;
		}

		public void Disconnect()
		{
			m_WebSocketStream.Close();
			m_TcpConnection.Disconnect();
			m_WebSocketStream = null;
			m_TcpConnection = null;
			m_OraBufPool = null;
		}

		public Stream GetStream()
		{
			return m_WebSocketStream;
		}

		public Socket GetSocket()
		{
			return null;
		}

		public Socket GetTestSocket()
		{
			return m_TcpConnection.GetTestSocket();
		}

		public bool UrgentDataSupported()
		{
			return false;
		}

		public void SendUrgent(byte[] data, int offset, int length)
		{
		}

		public void Send(OraBuf OB)
		{
			OraArraySegment[] the_ByteSegments = OB.the_ByteSegments;
			try
			{
				if (OB.the_ByteSegments_Count == 2)
				{
					m_WebSocketStream.Write(OB.m_buf, 0, OB.m_curlen);
					return;
				}
				for (int i = 0; i < OB.the_ByteSegments_Count; i++)
				{
					OraArraySegment oraArraySegment = the_ByteSegments[i];
					m_WebSocketStream.Write(oraArraySegment.Array, oraArraySegment.Offset, oraArraySegment.Count);
				}
			}
			catch (Exception inner)
			{
				throw new NetworkException(12571, inner);
			}
		}

		public void BeginAsyncReceives(OraBuf.AsyncReceiveCallback Callback, int AsyncBufferSize)
		{
		}

		public void Renegotiate(ConnectionOption conOption)
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.Renegotiate);
			}
			if (NeedReneg)
			{
				try
				{
					m_TcpConnection.Renegotiate(conOption);
				}
				catch (Exception inner)
				{
					throw new NetworkException(-6414, inner);
				}
				Stream stream = m_TcpConnection.GetStream();
				if (stream == null)
				{
					throw new NetworkException(-6414);
				}
				m_WebSocketStream.SetStream(stream);
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.Renegotiate);
			}
		}

		private void CreateTcpConnection(ConnectionOption conOption)
		{
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Entry, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.CreateTcpConnection);
			}
			if (string.Equals(conOption.Protocol, "wss", StringComparison.InvariantCultureIgnoreCase))
			{
				m_TcpConnection = new TcpsTransportAdapter(null);
				m_WSS = true;
			}
			else
			{
				if (!string.Equals(conOption.Protocol, "ws", StringComparison.InvariantCultureIgnoreCase))
				{
					throw new NetworkException(12538);
				}
				m_TcpConnection = new TcpTransportAdapter(null);
				m_WSS = false;
			}
			if (ProviderConfig.m_bTraceLevelNetwork)
			{
				string text = (m_WSS ? "TCPS" : "TCP") + "connection object created.\n";
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Sqlnet, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.CreateTcpConnection, text);
				Trace.Write(OracleTraceLevel.Network, OracleTraceTag.Exit, OracleTraceClassName.WssTransportAdapter, OracleTraceFuncName.CreateTcpConnection);
			}
		}
	}
}
